package com.sprite.utils.http;

import com.sprite.utils.UtilString;
import com.sprite.utils.text.InsensitiveString;
import com.sprite.utils.io.UtilIO;

import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;

/**
 * Http 工具类
 *
 * @author Jack
 */
public class UtilHttp {
    private static Headers defaultHeaders = new Headers();

    static {
        defaultHeaders.addHeader("user-agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36 SpriteUtilHttp/1.0");
    }

    /**
     * 在url追加参数
     *
     * @param url
     *         url
     * @param urlParam
     *         url参数
     * @throws UnsupportedEncodingException
     *         不支持的编码
     * @return 响应内容
     */
    private static String finalUrl(String url, UrlParams urlParam) throws UnsupportedEncodingException {
        if (urlParam == null) {
            return url;
        }

        return urlParam.appendToUrl(url);
    }

    /**
     * 发起一个请求
     * @param url url
     * @param method
     * @param headers
     * @param urlParams
     * @param requestPayload
     * @return
     * @throws Exception
     */
    public static HttpResponse request(String url, String method, Headers headers, UrlParams urlParams, RequestPayload requestPayload) throws Exception {
        url = finalUrl(url, urlParams);
        HttpURLConnection httpURLConnection = (HttpURLConnection) new URL(url).openConnection();
        httpURLConnection.setRequestMethod(method);
        if (headers != null) {
            for (Map.Entry<InsensitiveString, Object> header : headers.entrySet()) {
                httpURLConnection.setRequestProperty(header.getKey().getOriginal(), UtilString.toString(header.getValue()));
            }
        }

        for (Map.Entry<InsensitiveString, Object> header : defaultHeaders.entrySet()) {
            httpURLConnection.setRequestProperty(header.getKey().getOriginal(), UtilString.toString(header.getValue()));
        }

        if (requestPayload != null) {
            httpURLConnection.setDoOutput(true);
            if( requestPayload.getContentType() != null){
                httpURLConnection.setRequestProperty(HttpConstant.Header.CONTENT_TYPE, requestPayload.getContentType().toContentTypeString());
            }

            requestPayload.writePayload(httpURLConnection.getOutputStream());
        }

        return new DefaultHttpResponse(httpURLConnection);

    }

    public static HttpResponse get(String url) throws Exception {
        return request(url, HttpConstant.Method.GET, null, null, null);
    }

    /**
     * 获取数据流
     *
     * @param url
     *         url
     * @param headers
     *         请求都
     * @param urlParams
     *         url参数
     * @return 响应文本
     * @throws Exception
     *         http请求错误
     */
    public static InputStream getToStream(String url, Headers headers, UrlParams urlParams)
            throws Exception {
        HttpResponse response = request(url, HttpConstant.Method.GET, headers, urlParams, null);

        String contentType = response.getHeader(HttpConstant.Header.CONTENT_TYPE);
        String charset = null;
        if (contentType == null) {
            ContentType ctType = ContentType.resolve(contentType);
            charset = ctType.getCharset();
        }

        if (response.getStatusCode() != HttpURLConnection.HTTP_OK) {
            throw new HttpException(response.getStatusCode(), response.getStatusMessage(), UtilIO.readToText(response.getInputStream(), charset));
        }

        return response.getInputStream();
    }

    public static InputStream getToStream(String url) throws Exception {
        return getToStream(url, null, null);
    }

    /**
     * 获取响应内容
     *
     * @param url
     *         url
     * @param headers
     *         请求都
     * @param urlParams
     *         url参数
     * @return 响应文本
     * @throws Exception
     *         http请求错误
     */
    public static byte[] getToByte(String url, Headers headers, UrlParams urlParams)
            throws Exception {
        InputStream inputStream = getToStream(url, headers, urlParams);

        return UtilIO.readToBytes(inputStream);
    }

    /**
     * 获取响应内容
     *
     * @param url
     *         url
     * @throws Exception
     *         http请求错误
     * @return 响应内容
     */
    public static byte[] getToByte(String url)
            throws Exception {
        return getToByte(url, null, null);
    }

    /**
     * 获取响应文本
     *
     * @param url
     *         url
     * @param headers
     *         请求都
     * @param urlParams
     *         url参数
     * @return 响应文本
     * @throws Exception
     *         http请求错误
     */
    public static String getToText(String url, Headers headers, UrlParams urlParams)
            throws Exception {

        HttpResponse response = request(url, HttpConstant.Method.GET, headers, urlParams, null);


        String contentType = response.getHeader(HttpConstant.Header.CONTENT_TYPE);
        String charset = null;
        if (contentType != null) {
            ContentType ctType = ContentType.resolve(contentType);
            charset = ctType.getCharset();
        }

        if (response.getStatusCode() != HttpURLConnection.HTTP_OK) {
            throw new HttpException(response.getStatusCode(), response.getStatusMessage(), UtilIO.readToText(response.getInputStream(), charset));
        }

        return UtilIO.readToText(response.getInputStream(), charset);
    }

    public static String getToText(String url) throws Exception {
        return getToText(url, null, null);
    }

    /**
     * @param url
     *         url
     * @param headers
     *         请求头
     * @param urlParam
     *         url参数
     * @param requestPayload
     *         请求体
     * @return 响应文本
     * @throws Exception
     *         http请求出错
     */
    public static InputStream postToStream(String url, Headers headers, UrlParams urlParam, RequestPayload requestPayload)
            throws Exception {
        HttpResponse response = request(url, HttpConstant.Method.POST, headers, urlParam, requestPayload);


        String contentType = response.getHeader(HttpConstant.Header.CONTENT_TYPE);
        String charset = null;
        if (contentType == null) {
            ContentType ctType = ContentType.resolve(contentType);
            charset = ctType.getCharset();
        }

        if (response.getStatusCode() != HttpURLConnection.HTTP_OK) {
            throw new HttpException(response.getStatusCode(), response.getStatusMessage(), UtilIO.readToText(response.getInputStream(), charset));
        }

        return response.getInputStream();
    }

    /**
     * 获取响应内容
     *
     * @param url
     *         url
     * @param headers
     *         请求头
     * @param urlParams
     *         url参数
     * @param requestPayload
     *         请求体
     * @return 响应文本
     * @throws Exception
     *         http请求出错
     */
    public static byte[] postToByte(String url, Headers headers, UrlParams urlParams, RequestPayload requestPayload)
            throws Exception {
        InputStream inputStream = postToStream(url, headers, urlParams, requestPayload);

        return UtilIO.readToBytes(inputStream);
    }

    /**
     * 获取响应文本
     *
     * @param url
     *         url
     * @param headers
     *         请求头
     * @param urlParams
     *         url参数
     * @param requestPayload
     *         请求体
     * @return 响应文本
     * @throws Exception
     *         http请求出错
     */
    public static String postToText(String url, Headers headers, UrlParams urlParams, RequestPayload requestPayload)
            throws Exception {

        HttpResponse response = request(url, HttpConstant.Method.POST, headers, urlParams, requestPayload);


        String contentType = response.getHeader(HttpConstant.Header.CONTENT_TYPE);
        String charset = null;
        if (contentType != null) {
            ContentType ctType = ContentType.resolve(contentType);
            charset = ctType.getCharset();
        }

        if (response.getStatusCode() != HttpURLConnection.HTTP_OK) {
            throw new HttpException(response.getStatusCode(), response.getStatusMessage(), UtilIO.readToText(response.getInputStream(), charset));
        }

        return UtilIO.readToText(response.getInputStream(), charset);
    }

    public static void main(String[] args) throws Exception {
        String response = getToText("https://tools.ietf.org/html/rfc7233#section-4.1");
        System.out.println(response);
    }
}
